#include "fr_device_vbat.h"
#include "fr_device_charge.h"
#include "fr_watch.h"

uint16_t CH_Data[10];
uint8_t Bat_voltage = 0;
bool bat_filo_init_flag = false;
 /************************************************************************************
 * @fn      adc vbat start
 *
 * @brief   adc vbat start
 */
void device_vbat_init(enum_ADC_Demo_t fe_demo)
{
    adc_InitConfig_t ADC_Config;
    __SYSTEM_ADC_CLK_ENABLE();
    pmu_adc_power_ctrl(true);
    pmu_vbe_power_ctrl(true);

    switch(fe_demo)
    {
        case ADC_SOFTWARE_TRIGGER_MODE:
        {
            ADC_Config.ADC_Reference   = ADC_REF_IOLDO;
            ADC_Config.ADC_TriggerMode = ADC_SOFTWARE_TRIGGER;

			#if 0
            adc_set_channel_maping(0, ADC_CHANNEL_MAP_PMU_P4);
            adc_set_channel_maping(1, ADC_CHANNEL_MAP_PMU_P5);
            adc_set_channel_maping(2, ADC_CHANNEL_MAP_PMU_P6);
            adc_set_channel_maping(3, ADC_CHANNEL_MAP_PMU_P7);
            adc_set_channel_maping(4, ADC_CHANNEL_MAP_VABT);
            adc_set_channel_maping(5, ADC_CHANNEL_MAP_VBE);
			#else
			adc_set_channel_maping(4, ADC_CHANNEL_MAP_VBAT);
			#endif
            
            adc_init(ADC_Config);

			adc_soft_trigger_convert(4);

			while(!adc_get_channel_valid_status(4));

			uint16_t adc_result = adc_get_channel_data(4);
			uint16_t vbat_vol = adc_result * 4 * 3300 / 1023;

            //init filo
            if(!bat_filo_init_flag)
            {
                battery_value_fifo_init(vbat_vol);
                bat_filo_init_flag = true;
            }

            //transform to precentage
			//Bat_voltage = transform_battery(vbat_vol);
            Bat_voltage = battery_value_fifo_inc(transform_battery(vbat_vol));

            sync_cm3_data.battery.battery_value = Bat_voltage;

			printf("adc %d vol %d prec %d \r\n",adc_result,vbat_vol,Bat_voltage);

        }
		break;
		
        case ADC_HARDWARE_TRIGGER_LOOP_MODE:
        {
			ADC_Config.ADC_Reference   = ADC_REF_IOLDO;
            ADC_Config.ADC_TriggerMode = ADC_HARDWARE_TRIGGER;
            ADC_Config.HardTriggerConfig.ADC_Channel_Max  = 1;
            ADC_Config.HardTriggerConfig.ADC_Convert_Mode = ADC_LOOP_MODE;
            
            adc_init(ADC_Config);

            /*
                Conversion source : PMU_IO4~PMU_IO7 1/4VBAT VBE
                maping source     : Channel0~Channel7
                PMU_IO4 maping Channel0
                PMU_IO5 maping Channel1
                PMU_IO6 maping Channel2
                PMU_IO7 maping Channel3
                1/4VBAT maping Channel4
                    VBE maping Channel5
            */            
            
			#if 0
            adc_set_channel_maping(1, ADC_CHANNEL_MAP_PMU_P5);
            adc_set_channel_maping(2, ADC_CHANNEL_MAP_PMU_P6);
            adc_set_channel_maping(3, ADC_CHANNEL_MAP_PMU_P7);
            adc_set_channel_maping(4, ADC_CHANNEL_MAP_VBAT);
            adc_set_channel_maping(5, ADC_CHANNEL_MAP_VBE);
			#endif
            adc_set_channel_maping(0, ADC_CHANNEL_MAP_VBAT);
            adc_convert_start();
            while(!adc_get_channel_valid_status(0));
			uint16_t adc_result = adc_get_channel_data(0);
			uint16_t vbat_vol = adc_result * 4 * 3300 / 1023;

            //init filo
            if(!bat_filo_init_flag)
            {
                battery_value_fifo_init(vbat_vol);
                bat_filo_init_flag = true;
            }

            //transform to precentage
			//Bat_voltage = transform_battery(vbat_vol);
            Bat_voltage = battery_value_fifo_inc(transform_battery(vbat_vol));

            sync_cm3_data.battery.battery_value = Bat_voltage;

			printf("adc %d vol %d prec %d \r\n",adc_result,vbat_vol,Bat_voltage);
			#if 0
            while(1)
            {
                for (int i = 0; i < 6; i++)
                {
                    if (adc_get_channel_valid_status(i))
                    {
                        CH_Data[i] = adc_get_channel_data(i);
                        printf("Channel:%d, DATA:%d\r\n", i, CH_Data[i]);
                    }
                }
            }
			#endif
        }break;

        case ADC_HARDWARE_TRIGGER_IT_MODE:
        {
			#if 0
            ADC_Config.ADC_Reference   = ADC_REF_IOLDO;
            ADC_Config.ADC_TriggerMode = ADC_HARDWARE_TRIGGER;
            ADC_Config.HardTriggerConfig.ADC_Channel_Max  = 6;
            ADC_Config.HardTriggerConfig.ADC_Convert_Mode = ADC_LOOP_MODE;

            adc_init(ADC_Config);

            adc_set_channel_maping(0, ADC_CHANNEL_MAP_PMU_P4);
            adc_set_channel_maping(1, ADC_CHANNEL_MAP_PMU_P5);
            adc_set_channel_maping(2, ADC_CHANNEL_MAP_PMU_P6);
            adc_set_channel_maping(3, ADC_CHANNEL_MAP_PMU_P7);
            adc_set_channel_maping(4, ADC_CHANNEL_MAP_VABT);
            adc_set_channel_maping(5, ADC_CHANNEL_MAP_VBE);

            adc_convert_start_IT();
            
            NVIC_EnableIRQ(ADC_IRQn);

            while(1);
			#endif
        }break;
    }
}


/*
	get vbat voltage
*/
uint16_t device_get_vbat(void)
{
	return Bat_voltage;
}


/*
    adc vbat event handle
*/
void adc_vbat_event_handle(void)
{
    ool_write(PMU_REG_IOLDO1_CTRL_0, (ool_read(PMU_REG_IOLDO1_CTRL_0) & 0xf0) | 0x0a);
    device_vbat_init(ADC_HARDWARE_TRIGGER_LOOP_MODE);
    ool_write(PMU_REG_IOLDO1_CTRL_0, (ool_read(PMU_REG_IOLDO1_CTRL_0) & 0xf0) | 0x06);
}


/*
    adc vbat start detect
*/
void adc_vbat_start_detect(void)
{
	struct app_task_event *event;
	event = app_task_event_alloc(APP_TASK_EVENT_ADC_VBAT_DETECT, 0, false);
	if(event) 
	{
		//memcpy(event->param, (void *)&curr_button, sizeof(uint32_t));
		//event->param_len = sizeof(uint32_t);
		app_task_event_post(event, false);
	}
}



/*
	adc isr
*/
void adc_irq(void)
{
    for (int i = 0; i < 6; i++)
    {
        if (adc_get_channel_valid_status(i))
        {
            //printf("int channel: %d, DATA:%d\r\n", i, adc_get_channel_data(i));
        }
    }
}




const uint16_t g_battery_table[] =
{
    //0-10			//3405
    3405,			
    3410,
    3415,
    3420,
    3425,
    3430,
    3435,
    3440,
    3446,
    3452,

    //10-20			//3458
    3458,
    3464,
    3470,
    3476,
    3482,
    3488,
    3494,
    3500,
    3506,
    3512,

    //20-30			//3519
    3516,
    3520,
    3524,
    3528,
    3532,
    3536,
    3540,
    3544,
    3548,
    3552,

    //30-40			//3555
    3556,
    3560,
    3564,
    3568,
    3572,
    3576,
    3579,
    3582,
    3585,
    3588,

    //40-50			//3590
    3591,
    3594,
    3597,
    3602,
    3605,
    3608,
    3611,
    3614,
    3617,
    3620,

// 3800 --> 50%		//3623
    //50-60
    3623,
    3627,
    3631,
    3635,
    3639,
    3643,
    3647,
    3652,
    3657,
    3662,

// 3844
    //60-70			//3667
    3667,
    3673,
    3679,
    3685,
    3691,
    3697,
    3703,
    3710,
    3717,
    3724,
// 3920
    //70-80			//3731
    3731,
    3739,
    3747,
    3755,
    3763,
    3771,
    3779,
    3787,
    3795,
    3803,
//3980
    //80-90			//3812
    3811,
    3819,
    3827,
    3835,
    3843,
    3851,
    3859,
    3867,
    3875,
    3883,
//4040
    //90-100		//3830
    3900,
    3915,
    3930,
    3945,
    3960,
    3975,
    3990,
    4005,
    4020,
    4050,

};



uint8_t transform_battery(uint16_t battery_value)
{
    uint8_t i = 100;

    while(i > 0)
    {
        if(battery_value >= g_battery_table[i - 1])
        {
            break;
        }
        i --;
    }

    return i;
    
}

#define  BATTERY_FIFO_MAX	20
uint8_t battery_detect_fifo[BATTERY_FIFO_MAX];

void battery_value_fifo_init(uint16_t value)
{
	uint8_t voltage = transform_battery(value);

	for(uint8_t i = 0; i < BATTERY_FIFO_MAX; i ++ )
	{
		battery_detect_fifo[i] = voltage;
  	}

	Bat_voltage = voltage;
}

uint8_t battery_value_fifo_inc(uint8_t value)
{

	for(uint8_t i = 0; i < (BATTERY_FIFO_MAX - 1); i ++ )
	{
		battery_detect_fifo[(BATTERY_FIFO_MAX - 1) - i] = battery_detect_fifo[(BATTERY_FIFO_MAX - 2) - i];
    }
	battery_detect_fifo[0] = value;

	uint32_t battery_total = 0;
	for(uint8_t i = 0; i < BATTERY_FIFO_MAX; i ++ )
	{
		battery_total += battery_detect_fifo[i];
    }

	uint8_t averages = battery_total / BATTERY_FIFO_MAX;
	
	if(get_charge_status() == CHARGING_IN)
	{
		return averages;
	}
	else
	{
		if(averages > Bat_voltage)
		{
			return Bat_voltage;
		}
		else
		{
			return averages;
		}
	}

}















